package tr.helper.controller.sprite;

import cn.hutool.core.img.BackgroundRemoval;
import com.github.kwhat.jnativehook.GlobalScreen;
import com.github.kwhat.jnativehook.keyboard.NativeKeyEvent;
import com.github.kwhat.jnativehook.keyboard.NativeKeyListener;
import com.github.kwhat.jnativehook.mouse.NativeMouseEvent;
import com.github.kwhat.jnativehook.mouse.NativeMouseInputListener;
import java.awt.AWTException;
import java.awt.Color;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import org.apache.commons.lang3.StringUtils;
import tr.helper.CommonUtil;
import tr.helper.controller.SecurityController;

/**
 * tr-service
 *
 * @author MrYe
 * @date 2022-01-21 14:28
 */
public class SpriteController extends SecurityController implements NativeKeyListener, NativeMouseInputListener {

    @FXML
    public Button btnStart;
    @FXML
    public Button btnStop;
    @FXML
    public TextField txtPwd;
    @FXML
    public TextField txtInterval;
    @FXML
    public TextField txtClose;
    @FXML
    public Button btnReg;
    @FXML
    public TextField txtConf;

    @FXML
    private ListView listLog;

    @FXML
    private TextField txtLoc1;

    @FXML
    public TextField txtLoc2;

    Service<Double> service;

    Robot robot;

    private int run = 0;

    private int reg = 0;

    private ObservableList items = FXCollections.observableArrayList();

    @Override
    public void init(URL location, ResourceBundle resources) {
        try {
            robot = new Robot();
        } catch (AWTException e) {
            e.printStackTrace();
        }
    }

//    Random random = new Random();
//        while (true) {
//        try {
//            robot.mouseMove(400 + random.nextInt(100), 400 + random.nextInt(100));
//            PointerInfo a = MouseInfo.getPointerInfo();
//            Point b = a.getLocation();
//            int x = (int) b.getX();
//            int y = (int) b.getY();
//            addLog("当前鼠标坐标 x=" + x + " y=" + y);
//            Thread.sleep(5000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//    }

    @FXML
    public void doReg() {
        if (reg == 0) {
            try {
                GlobalScreen.registerNativeHook();
            } catch (Exception ex) {
                System.err.println("There was a problem registering the native hook.");
                System.err.println(ex.getMessage());
                System.exit(1);
            }
            GlobalScreen.addNativeKeyListener(this);
            GlobalScreen.addNativeMouseListener(this);
            GlobalScreen.addNativeMouseMotionListener(this);
            reg = 1;
            addLog("注册键盘鼠标监听事件成功");
            btnReg.setText("卸载监听");
        } else {
            try {
                GlobalScreen.unregisterNativeHook();
            } catch (Exception ex) {
                System.err.println("There was a problem unregistering the native hook.");
                System.err.println(ex.getMessage());
                System.exit(1);
            }
            GlobalScreen.removeNativeKeyListener(this);
            GlobalScreen.removeNativeMouseListener(this);
            GlobalScreen.removeNativeMouseMotionListener(this);
            reg = 0;
            addLog("卸载监听键盘鼠标监听事件成功");
            btnReg.setText("注册监听");
            doStop();
        }
    }

    @FXML
    public void doStart() {
        clearLog();
        addLog("开始");
        service = new Service<Double>() {
            @Override
            protected Task<Double> createTask() {
                return new Task<Double>() {
                    @Override
                    protected Double call() {
                        Platform.runLater(() -> {
                            btnStart.setDisable(true);
                            btnStop.setDisable(false);
                        });
                        run = 1;
                        try {
                            begin();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        Platform.runLater(() -> {
                            btnStart.setDisable(false);
                            btnStop.setDisable(true);
                        });
                        return null;
                    }
                };
            }
        };
        Platform.runLater(service::start);
    }

    @FXML
    public void doStop() {
        addLog("停止");
        run = 0;
        service.cancel();
        btnStart.setDisable(false);
        btnStop.setDisable(true);
    }

    private void begin() throws InterruptedException {
        final String osName = CommonUtil.getOsName();
        int control = KeyEvent.VK_CONTROL;
        if (StringUtils.containsIgnoreCase(osName, "mac")) {
            control = KeyEvent.VK_META;
        }
        //将账号放置到剪切板中
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents(new StringSelection(txtPwd.getText()), null);
        addLog("复制密码[" + txtPwd.getText() + "]");
        int i = 0;

        while (run == 1) {
            String loc1 = txtLoc1.getText();
            String loc2 = txtLoc2.getText();
            String close = txtClose.getText();
            if (StringUtils.isBlank(loc1) || StringUtils.isBlank(loc2) || StringUtils.isBlank(close)) {
                Thread.sleep(3000L);
                continue;
            }
            // 普通模式
            if ("debug".equals(txtConf.getText())) {
                robot.mouseMove(CommonUtil.asInt(loc1.split("-")[0]), CommonUtil.asInt(loc1.split("-")[1]));
                addLog("移动到位置1");

                lefClick();

                //clear(control);
                // mac control = 3675 VC_META  windows = VK_CONTROL
                //past(control);

                //addLog("删除原文本框数据，粘贴密码[" + txtPwd.getText() + "]");

                robot.mouseMove(CommonUtil.asInt(loc2.split("-")[0]), CommonUtil.asInt(loc2.split("-")[1]));
                addLog("移动到位置2");

                lefClick();
                Thread.sleep(Long.parseLong(txtInterval.getText()));
                continue;
            }

            robot.mouseMove(CommonUtil.asInt(loc2.split("-")[0]), CommonUtil.asInt(loc2.split("-")[1]));
            addLog("移动到确认按钮位置");

            Color mouseColor = getMouseColor();
            final boolean isBlue = isSureBtnColor(mouseColor);
            if (!isBlue) {
                addLog("未检测到唤起支付事件!");
                Thread.sleep(1000L);
                continue;
            }

            lefClick();

            int temp = 0;
            while (true) {
                Color mouseColor2 = getMouseColor();
                if (mouseColor2 != mouseColor) {
                    temp = 1;
                }
                if (temp == 1 && isSureBtnColor(mouseColor2)) {
                    addLog("弹框已完成弹出！！！");
                    robot.delay(200);
                    break;
                }
            }

            robot.mouseMove(CommonUtil.asInt(loc1.split("-")[0]), CommonUtil.asInt(loc1.split("-")[1]));
            addLog("移动到输入密码位置");

            // left click
            lefClick();
            robot.delay(20);
            lefClick();

            robot.delay(200);
            clear(control);
            // mac control = 3675 VC_META  windows = VK_CONTROL
            past(control);

            robot.delay(200);
            addLog("删除原文本框数据，粘贴密码[" + txtPwd.getText() + "]");

            robot.mouseMove(CommonUtil.asInt(loc2.split("-")[0]), CommonUtil.asInt(loc2.split("-")[1]));

            addLog("移动到确认按钮位置");

            mouseColor = getMouseColor();

            lefClick();

            temp = 0;
            while (true) {
                Color mouseColor2 = getMouseColor();
                if (mouseColor2 != mouseColor) {
                    temp = 1;
                }
                if (temp == 1 && isSureBtnColor(mouseColor2)) {
                    addLog("再次确认弹窗弹出！！！");
                    robot.delay(200);
                    break;
                }
            }

            robot.mouseMove(CommonUtil.asInt(loc2.split("-")[0]), CommonUtil.asInt(loc2.split("-")[1]));
            lefClick();

            temp = 0;
            boolean isFailed = false;
            int inc = 0;
            while (true) {
                inc++;
                Color mouseColor2 = getMouseColor();
                if (mouseColor2 != mouseColor) {
                    temp = 1;
                }
                if (temp == 1 && isSureBtnColor(mouseColor2)) {
                    addLog("当前最后一次确认弹窗弹出！！！");
                    break;
                }
                if (inc > 120) {
                    addLog("抢失败！！！触发关闭");
                    isFailed = true;
                    break;
                }
            }

            if (isFailed) {
                robot.mouseMove(CommonUtil.asInt(close.split("-")[0]), CommonUtil.asInt(close.split("-")[1]));
                lefClick();
                continue;
            }

            robot.mouseMove(CommonUtil.asInt(loc1.split("-")[0]), CommonUtil.asInt(loc1.split("-")[1]));
            addLog("移动到输入密码位置");

            // left click
            lefClick();
            robot.delay(20);
            lefClick();

            robot.delay(200);
            clear(control);
            // mac control = 3675 VC_META  windows = VK_CONTROL
            past(control);

            robot.delay(200);
            addLog("删除原文本框数据，粘贴密码[" + txtPwd.getText() + "]");

            robot.mouseMove(CommonUtil.asInt(loc2.split("-")[0]), CommonUtil.asInt(loc2.split("-")[1]));

            addLog("移动到确认按钮位置");

            mouseColor = getMouseColor();

            lefClick();

            while (true) {
                Color mouseColor2 = getMouseColor();
                if (mouseColor2 != mouseColor) {
                    break;
                }
            }

            i++;

            addLog("第" + i + "次点击确认，不想继续请按键盘Q");

            Thread.sleep(Long.parseLong(txtInterval.getText()));
        }
    }

    private void clear(int control) {
        robot.keyPress(control);
        //按下 a
        robot.keyPress(KeyEvent.VK_A);
        //松开ctrl
        robot.keyRelease(control);
        robot.keyRelease(KeyEvent.VK_A);

        //按下 DEL
        robot.keyPress(KeyEvent.VK_DELETE);
        //松开 DEL
        robot.keyRelease(KeyEvent.VK_DELETE);
        //间隔时间
        //robot.delay(20);
    }

    private void past(int control) {
        copy();
        robot.keyPress(control);
        //按下 v
        robot.keyPress(KeyEvent.VK_V);
        //松开ctrl
        robot.keyRelease(control);
        //松开v
        robot.keyRelease(KeyEvent.VK_V);
        //间隔时间
        //robot.delay(200);
    }

    private void copy() {

        //将账号放置到剪切板中
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents(new StringSelection(txtPwd.getText()), null);
        addLog("复制密码[" + txtPwd.getText() + "]");
    }

    private void lefClick() {
        robot.mousePress(InputEvent.BUTTON1_MASK);
        robot.mouseRelease(InputEvent.BUTTON1_MASK);
    }

    @Override
    public void nativeKeyPressed(NativeKeyEvent e) {
        System.out.println("Key Pressed: " + NativeKeyEvent.getKeyText(e.getKeyCode()) + " keyCode: " + e.getKeyCode());
        if (e.getKeyCode() == NativeKeyEvent.VC_Q) {
            doStop();
        }
        if (e.getKeyCode() == NativeKeyEvent.VC_F1) {
            PointerInfo point = MouseInfo.getPointerInfo();
            Point location = point.getLocation();
            txtLoc1.setText(CommonUtil.asString(location.getX()) + "-" + CommonUtil.asString(location.getY()));
        }
        if (e.getKeyCode() == NativeKeyEvent.VC_F2) {
            PointerInfo point = MouseInfo.getPointerInfo();
            Point location = point.getLocation();
            txtLoc2.setText(CommonUtil.asString(location.getX()) + "-" + CommonUtil.asString(location.getY()));
        }
        if (e.getKeyCode() == NativeKeyEvent.VC_F3) {
            PointerInfo point = MouseInfo.getPointerInfo();
            Point location = point.getLocation();
            txtClose.setText(CommonUtil.asString(location.getX()) + "-" + CommonUtil.asString(location.getY()));

            Color color = getMouseColor();
            int r = color.getRed();
            int g = color.getGreen();
            int b = color.getBlue();
            addLog("当前是否蓝色按钮=" + isSureBtnColor(color) + " 容差=" + txtConf.getText() + " red=" + r + " green=" + g + " blue=" + b);
        }
        if (e.getKeyCode() == NativeKeyEvent.VC_F4) {
            clearLog();
        }
    }

    private boolean isSureBtnColor(Color color) {
        return BackgroundRemoval.areColorsWithinTolerance(color, Color.blue, CommonUtil.asInt(txtConf.getText()));
    }

    private Color getMouseColor() {
        PointerInfo point = MouseInfo.getPointerInfo();
        Point location = point.getLocation();
        return robot.getPixelColor(location.x, location.y);
    }

    @Override
    public void nativeMouseClicked(NativeMouseEvent e) {
        //System.out.println("Mouse Clicked: " + e.getClickCount());
    }

    @Override
    public void nativeMousePressed(NativeMouseEvent e) {
        //System.out.println("Mouse Pressed: " + e.getID());
    }

    @Override
    public void nativeMouseReleased(NativeMouseEvent e) {
        //System.out.println("Mouse Released: " + e.getButton());
    }

    @Override
    public void nativeMouseMoved(NativeMouseEvent e) {
        //System.out.println("Mouse Moved: " + e.getX() + ", " + e.getY());
    }

    public void clearLog() {
        addLog("", true);
    }

    public void addLog(String msg) {
        addLog(msg, false);
    }

    public void addLog(String msg, boolean clear) {
        Platform.runLater(() -> {
            if (clear) {
                items.clear();
            } else {
                items.add(msg);
            }
            listLog.setItems(items);
        });
    }

}
